#include "literal.h"
#include <stdio.h>
#include "expresion.h"
#include "abcyp.h"

#define VAR "x"
#define OK 1
#define ERROR_N_FOUND 0
#define ERROR 0

char *program_name;
char **aux=NULL;
int debbug=0;
/*
 *Muestra la forma correcta de ejecucion del programa
 */
void uso(void){
    fprintf(stderr,"Sintaxis\n");
    fprintf(stderr,"%s <formula a derivar> [-D], o [-a -D]\n",program_name);
    fprintf(stderr,"%s -a <archivo>\n",program_name);
    fprintf(stderr,"%s -D Modo debbug\n",program_name);
    exit (8);
}
/*
 *verifica la existencia del archivo indicado
 */


/* FUNCION CREADA PARA DEBBUG.
PRE: Recibe un puntero a un arbol y un string para identificar la pocicion actual.
POS: Recorre el arbol y muestra el contenido de sus ramas y la pocicion que le corresponde*/
void recorrer_AB(TAB* expr,const char* nodo,char *salida){
    int error;
    char* nodo2;
    char* linea;
    TLiteral literal;
    AB_ElemCte(*expr,&literal);
    if (!strcmp(nodo," "))
        nodo2=strdup("RAIZ");
    else{
    }
    AB_ElemCte(*expr,&literal);
    Literal_AString(&literal,&linea);
    sprintf(salida,"%s%s: %s\n",salida,nodo,linea);
    Literal_Destruir(&literal);
    free(linea);

    AB_MoverCte(expr,IZQ,&error);
    if (!error){
        nodo2=(char*)malloc(sizeof(char)*(strlen(nodo)+5));
        strcpy(nodo2,nodo);
        strcat(nodo2,"-IZQ");
        recorrer_AB(expr,nodo2,salida);
        free(nodo2);
    }
    AB_MoverCte(expr,DER,&error);

    if (!error){
        nodo2=(char*)malloc(sizeof(char)*(strlen(nodo)+5));
        strcpy(nodo2,nodo);
        strcat(nodo2,"-DER");
        recorrer_AB(expr,nodo2,salida);
        free(nodo2);
    }
    AB_MoverCte(expr,PAD,&error);
}


int procesarExpresion(char *expresion,char *salida){

    TLiteral literal;
    TExpresion expr,destino,destino2,destino3;
    char *string;
    int error;
    Expresion_Crear (&expr);
    Expresion_Parsear (&expr, expresion, VAR);
    error=Expresion_Simplificar(&expr,&destino);
    sprintf(salida,"%sFormula a derivar: %s\n",salida,expresion);
    if(error!=1){
        if(error==-3){
          fprintf(stderr,"MA Error para: %s\n",expresion);
          sprintf(salida,"%sMA Error para: %s\n",salida,expresion);
        }
        Expresion_Destruir(&expr);
        if (debbug) printf("%d\n",error);
        return 1;
    }
    if (debbug)recorrer_AB(&destino,"RAIZ",salida);
    Expresion_Derivar(&destino,&destino2);
    if (debbug) sprintf(salida,"%sDerivo\n",salida);
    Expresion_AString (&destino2, &string);
    if (debbug) sprintf(salida,"%sFormula derivada: %s\n",salida,string);
    free(string);
    error=Expresion_Simplificar(&destino2,&destino3);
    if(error!=1){
        if(error==-3) fprintf(stderr,"MA Error para: %s\n",expresion);
        if (debbug) sprintf(salida,"%sERROR: %d\n",salida,error);
        Expresion_Destruir(&expr);
        return 1;
    }
    Expresion_AString (&destino3, &string);
    if (debbug)
      sprintf(salida,"%sFormula derivada y simplificada: %s\n",salida,string);
    else
      sprintf(salida,"%sFormula derivada: %s\n",salida,string);
    free(string);
    Expresion_Destruir (&expr);
    Expresion_Destruir (&destino);
    Expresion_Destruir (&destino2);
    Expresion_Destruir (&destino3);
}

int file_exists(char *filename){
    FILE * file;
    file = fopen(filename, "r");
    if (file!=NULL){ /*Prueba de apertura para lectura*/
        fclose(file);
        return OK;/*el archivo existe*/
    }
    return ERROR_N_FOUND;
}
int obtenerLinea(FILE *entrada, char *expresion){

    if (fscanf(entrada,"%s",expresion)!=EOF){
        return 1;
    }
    return 0;
}
int esExpresion(char *expresion, char *salida){

    TPila pila;
    int error;
    P_Crear(&pila, sizeof(TLiteral));
    error=infijo_a_sufijo(expresion,"x",&pila);
    if (error!=1){
        sprintf(salida,"%sError en TDA LITERAL: %d",salida,error);
        return 0;
    }
    P_Vaciar(&pila);
    if (debbug) sprintf(salida,"%sExpresion OK\n",salida);
    return 1;
}
int main(int argc, char* argv[]) {
    FILE *archIn, *archOut;
    char *string, *entrada, *expresion, *salida;
    int i,tope;

    /* Nobre de ejecucion para salidas de error e informacion */
    program_name = argv[0];
    entrada = NULL;
    if (argc == 1)uso();
   /*Comprobacion modo debbug*/
    for(i=0;i<argc;i++)
        if (!strcmp(argv[i],"-D")){
            argc--;
            i--;
            debbug=1;
        }else{
            aux = (char**)realloc(aux,sizeof(char**)*(i+1));
            aux[i]=malloc((strlen(argv[i])+1)*sizeof(char*));
            memcpy(aux[i],argv[i],(strlen(argv[i])+1)*sizeof(char*));
        }
    tope = argc-1;
    expresion = (char *)malloc(sizeof(char*)*100);
    if (debbug) fprintf(stderr,"Modo debbug\n");
    if (debbug) fprintf(stderr,"parametro 1 %s\n",argv[1]);
    if (debbug) fprintf(stderr,"parametro 2 %s\n",argv[2]);
    /*si solo tiene un parametro expresion*/
    if (argc == 2 && esExpresion(argv[1],salida))
        sprintf(expresion,"%s",argv[1]);

    while ((argc >= 2) && (argv[1][0] == '-')) {
      switch (argv[1][1]) {
        case 'a':
          if (argv[2]!=NULL){
            entrada = argv[2];
            if ( file_exists(entrada)==OK){
              archIn = fopen(entrada,"r");
            }else{
              fprintf(stderr,"No se encontro %s para la opcion -a\n",entrada);
              if (aux){
                for (i=0;i<argc;i++)
                  free(aux[i]);
                free(aux);
              }
              uso();
            }
          }
          break;
          case 'f':
            if (argv[2])
              sprintf(expresion,"%s",argv[2]);
            else
              if (aux){
                for (argc;i>=0;--i)
                  free(aux[i]);
                free(aux);
              }
              uso();
          break;
          default:
            if (aux){
              for (argc;i>=0;--i)
                free(aux[i]);
              free(aux);
            }
            uso();
          break;
      }
      /*
      * aumento la lista de argumentos
      * bajo la cantidad de argumentos
      */
      argv = argv + 2;
      argc = argc - 2;
    }
    salida = malloc(sizeof(char*)*5000);
    if (entrada){/*archivo*/

        sprintf(salida,"%s.out",entrada);
        archOut = fopen(salida,"w");
        if (!archOut)return -1;
        sprintf(salida,"");
        while (obtenerLinea(archIn,expresion))
            if (esExpresion(expresion,salida)){
                procesarExpresion(expresion,salida);
                fprintf(archOut,"%s\n",salida);
                sprintf(salida,"");
            }
        fclose(archIn);
        fclose(archOut);
    }else{/*string*/
        sprintf(salida,"-");
        if (esExpresion(expresion,salida))
            procesarExpresion(expresion,salida);
        fprintf(stdout,"%s",salida);

    }
    free(expresion);
    if (aux){
      for (i=tope;i>-1;--i)
          free(aux[i]);
      free(aux);
    }
    free(salida);
    return 0;
}


